package com.lt.integration.jpa.component.hibernate.json;

import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
import org.hibernate.type.descriptor.java.MutableMutabilityPlan;
import org.hibernate.usertype.DynamicParameterizedType;

import java.util.Properties;


/**
 * @author Vlad Mihalcea
 */
public class JsonTypeDescriptor extends AbstractTypeDescriptor<Object> implements DynamicParameterizedType {

	private static final long serialVersionUID = -486088919495243585L;
	
	//不能使用单列模式
//	public static final JsonTypeDescriptor INSTANCE = new JsonTypeDescriptor();
	
	private Class<?> clazz;

    @Override
    public void setParameterValues(Properties parameters) {
    	clazz = ( (ParameterType) parameters.get( PARAMETER_TYPE ) ).getReturnedClass();
    }

//    @SuppressWarnings("serial")
//	public JsonTypeDescriptor() {
//        super( Object.class, new MutableMutabilityPlan<Object>() {
//            @Override
//            protected Object deepCopyNotNull(Object value) {
//            	String str = JSON.toJSONString(value);
//                return JSON.parseObject(str, value.getClass());
//            }
//        });
//    }
    
    @SuppressWarnings("serial")
    public JsonTypeDescriptor() {
        super( Object.class, new MutableMutabilityPlan<Object>() {
            @Override
            protected Object deepCopyNotNull(Object value) {
                return JacksonUtil.clone(value);
            }
        });
    }

    @Override
    public boolean areEqual(Object one, Object another) {
        if ( one == another ) {
            return true;
        }
        if ( one == null || another == null ) {
            return false;
        }
        
        return JacksonUtil.toJsonNode(JacksonUtil.toString(one)).equals(
                JacksonUtil.toJsonNode(JacksonUtil.toString(another)));
    }

//    @Override
//    public String toString(Object value) {
//        return JSON.toJSONString(value, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.DisableCircularReferenceDetect);
//    }
    
    @Override
    public String toString(Object value) {
        return JacksonUtil.toString(value);
    }
    
    @Override
    public Object fromString(String string) {
        return JacksonUtil.fromString(string, clazz);
    }

//    @Override
//    public Object fromString(String str) {
//    	return JSON.parseObject(str, clazz);
//    }

    @SuppressWarnings({ "unchecked" })
    @Override
    public <X> X unwrap(Object value, Class<X> type, WrapperOptions options) {
        if ( value == null ) {
            return null;
        }
        if ( String.class.isAssignableFrom( type ) ) {
            return (X) toString(value);
        }
        throw unknownUnwrap( type );
    }

    @Override
    public <X> Object wrap(X value, WrapperOptions options) {
        if ( value == null ) {
            return null;
        }
        return fromString(value.toString());
    }

}
